package cn.faifai.tagapi.service;

import cn.hutool.core.bean.BeanUtil;
import cn.faifai.common.page.TableDataInfo;
import cn.faifai.tagapi.dto.PageQuery;
import cn.faifai.tagapi.dto.TagDTO;
import cn.faifai.tagapi.dto.TagSerialize;
import cn.faifai.tagapi.entity.Tag;
import cn.faifai.common.exception.ServiceException;
import cn.faifai.tagapi.repository.TagRepository;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class TagService {
    @Autowired
    TagRepository tagRepository;

    public Tag save(TagDTO tagDTO){
        if (tagDTO.getId() == null && tagDTO.getParentId() == null){
            throw new ServiceException("parentId不能为空");
        }
        Tag add = BeanUtil.toBean(tagDTO, Tag.class);
        return tagRepository.save(add);
    }

    public Page<Tag> getTagListByParentId(Long parentId, PageQuery pageQuery){
        Page<Tag> tagPage = tagRepository.findByParentId(parentId, PageRequest.of(pageQuery.getJPAPageNum(), pageQuery.getPageSize()));
        return tagPage;
    }

    /**
     * 删除标签
     */
    public void delete(List<Long> ids){
        tagRepository.deleteAllById(ids);
    }


    /**
     * 构造动态条件
     */
    public Specification<Tag> TagSpecification(TagDTO tagDTO) {
        return (Root<Tag> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (tagDTO.getName() != null) {
                predicates.add(cb.equal(root.get("name"), tagDTO.getName()));
            }

            if (tagDTO.getParentId() != null) {
                predicates.add(cb.equal(root.get("parentId"), tagDTO.getParentId()));
            }

            // 返回所有条件的组合 new Predicate[0]避免空指针，
            /**
             * 学习笔记：
             * 当调用 predicates.toArray(new Predicate[0]) 时，我们实际上是在请求 toArray 方法根据 predicates 列表的大小（包括空列表的情况）来创建一个新的 Predicate 数组，并填充列表中的所有元素（如果有的话）。
             * 对于空列表，toArray(new Predicate[0]) 将直接返回传入的 new Predicate[0] 数组，即一个长度为0的数组。
             * 这个长度为0的数组随后被传递给 cb.and(...) 方法。由于 cb.and(...) 能够处理空数组作为输入，并返回一个总是为真的 Predicate，因此这种方式是安全的，可以避免在没有任何条件时发生空指针异常。
             */
            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }

    /**
     * 通过id查询tag
     */
    public TagSerialize getTagById(Long id){
        return tagRepository.findTagsWithFilesById(id).orElseThrow(() -> new ServiceException("标签不存在"));
    }
    /**
     * 分页查询标签列表
     */
    public TableDataInfo getTagPageList(TagDTO tagDTO, PageQuery pageQuery){
        // like查询Tag的name字段
        ExampleMatcher matching = ExampleMatcher.matching()
                .withMatcher("name",m->m.contains());
        Page<Tag> all = tagRepository.findAll(
                Example.of(
                        BeanUtil.toBean(tagDTO, Tag.class),matching),
                PageRequest.of(
                        pageQuery.getJPAPageNum(),
                        pageQuery.getPageSize()));
        return TableDataInfo.build(all);
    }

    /**
     * 分页查询标签列表
     */
    public TableDataInfo getTagDTOPageList(TagDTO tagDTO, PageQuery pageQuery){
        // like查询Tag的name字段
        ExampleMatcher matching = ExampleMatcher.matching()
                .withMatcher("name",m->m.contains());
        Page<Tag> all = tagRepository.findAll(
                Example.of(
                        BeanUtil.toBean(tagDTO, Tag.class),matching),
                PageRequest.of(
                        pageQuery.getJPAPageNum(),
                        pageQuery.getPageSize()));
        // 将Tag实体列表转换为TagDTO列表
        List<TagDTO> dtoList = all.getContent().stream()
                .map(i -> BeanUtil.toBean(i, TagDTO.class))
                .collect(Collectors.toList());

        // 构建新的Page对象，因为原来的Page对象包含的是Tag实体而不是TagDTO
        Page<TagDTO> dtoPage = new PageImpl<>(dtoList, all.getPageable(), all.getTotalElements());
        return TableDataInfo.build(dtoPage);
    }

    /**
     * 是否存在子节点
     */
    public boolean hasChild(Long tagId) {
        return tagRepository.countByParentId(tagId) > 0;
    }
}
